package nivod

import (
	"github.com/gogf/gf/v2/crypto/gmd5"
	"github.com/gogf/gf/v2/os/gctx"
	"github.com/gogf/gf/v2/os/gtime"
	"github.com/gogf/gf/v2/text/gregex"
	"github.com/gogf/gf/v2/text/gstr"
	"github.com/tebeka/selenium"
	"time"
	"uni-crawl-frame/core"
	"uni-crawl-frame/db/mysql/dao"
	"uni-crawl-frame/db/mysql/model/do"
	"uni-crawl-frame/db/mysql/model/entity"
	"uni-crawl-frame/service/crawl/vodservice"
	"uni-crawl-frame/service/lockservice"
	"uni-crawl-frame/utils/browserutil"
	"uni-crawl-frame/utils/constant"
)

const (
	videoItemXpath = "//*[@class='qy-mod-ul']/li//*[@class='qy-list-img vertical']"
	videoListXpath = "//*[@class='qy-mod-ul']"
	WaitSeconds    = gtime.S * 5
)

type NiVodTVTask struct {
	*core.AbstractCrawlByBrowser
}

func (r *NiVodTVTask) UseCrawlerProxy() bool {
	return true
}

func (r *NiVodTVTask) UseBrowserMobProxy() bool {
	return false
}

func (r NiVodTVTask) OpenBrowser(ctx *core.ApplicationContext) {

	if ctx.CrawlVodCtx != nil {
		openBrowserForVodConfig(ctx)
	} else if ctx.CrawlTVCtx.VodTV != nil {
		openBrowserForPadInfo(ctx)
	}

}

func openBrowserForVodConfig(ctx *core.ApplicationContext) {
	ctx.Log.Infof(gctx.GetInitCtx(),
		"vod config task. SeedUrl = %v", ctx.CrawlVodCtx.SeedUrl)
	_ = ctx.Wd.Get(ctx.CrawlVodCtx.SeedUrl)
	_ = ctx.Wd.WaitWithTimeout(func(wd selenium.WebDriver) (bool, error) {
		ulEle, _ := wd.FindElement(selenium.ByXPATH, videoListXpath)
		if ulEle == nil {
			return false, nil
		}
		liEleArray, _ := ulEle.FindElements(selenium.ByXPATH, "li")
		if len(liEleArray) == 0 {
			return false, nil
		}
		return true, nil
	}, WaitSeconds)

	for i := 0; i < ctx.CrawlVodCtx.CmsCrawlVodConfig.PageSize; i++ {
		_, _ = ctx.Wd.ExecuteScript(browserutil.ScrollBottomJs, nil)
		waitPageSeconds := 2
		lockservice.AddSeleniumExpireTime(waitPageSeconds)
		time.Sleep(gtime.S * time.Duration(waitPageSeconds))
	}

	vodTvElements, _ := ctx.Wd.FindElements(selenium.ByXPATH, videoItemXpath)
	ctx.Log.Infof(gctx.GetInitCtx(),
		"vod config task. 视频列表数 = %v", len(vodTvElements))

	for _, vodTvEle := range vodTvElements {
		aEle, aErr := vodTvEle.FindElement(selenium.ByXPATH, ".//*[@class='title-wrap']//a")
		href, _ := aEle.GetAttribute("href")
		title, _ := aEle.GetAttribute("title")

		imgEle, imgErr := vodTvEle.FindElement(selenium.ByXPATH, ".//*[@class='qy-mod-link-wrap']//*[@id='T-randomAni']")
		stypeStr, _ := imgEle.GetAttribute("style")
		matches, _ := gregex.MatchString("http.*jpg", stypeStr)
		imgSrc := ""
		if len(matches) > 0 {
			imgSrc = matches[0]
		}
		if aErr != nil || imgErr != nil || href == "" || title == "" {
			continue
		}

		tvMd5 := gmd5.MustEncryptString(href)
		vodTv := vodservice.GetVodTvByMd5(tvMd5)
		if vodTv != nil {
			continue
		}
		ctx.Log.Infof(gctx.GetInitCtx(),
			"title : %s, link = %s", title, href)

		tv := new(do.CmsCrawlVodTv)
		tv.CrawlStatus = vodservice.CrawlTVInit
		tv.VodConfigId = ctx.CrawlVodCtx.VodConfigId
		tv.VodMd5 = tvMd5
		tv.VideoName = title
		tv.SeedUrl = href
		tv.VideoIcon = imgSrc
		tv.CreateTime = gtime.Now()
		_, _ = dao.CmsCrawlVodTv.Ctx(gctx.GetInitCtx()).Insert(tv)
	}
}

func openBrowserForPadInfo(ctx *core.ApplicationContext) {
	crawlTvDto := ctx.CrawlTVCtx.VodTV
	ctx.Log.Infof(gctx.GetInitCtx(),
		"pad info. id = %v, SeedUrl = %v", crawlTvDto.Id, crawlTvDto.SeedUrl)
	titleXPath := "//*[@class='header-link']"
	_ = ctx.Wd.Get(crawlTvDto.SeedUrl)
	_ = ctx.Wd.WaitWithTimeout(func(wd selenium.WebDriver) (bool, error) {
		title := browserutil.GetTextByXpath(wd, titleXPath)
		if isEmptyNiVodElement(title) {
			return false, nil
		}
		return true, nil
	}, WaitSeconds)

	title := browserutil.GetTextByXpath(ctx.Wd, titleXPath)
	ctx.Log.Infof(gctx.GetInitCtx(),
		"pad info. crawl title = %v", title)
	if isEmptyNiVodElement(title) {
		crawlTvDto.ErrorCnt += 1
		if crawlTvDto.ErrorCnt >= constant.ServerMaxRetry {
			ctx.Log.Infof(gctx.GetInitCtx(),
				"pad info update vod id = %v, to status = %v", crawlTvDto.Id, vodservice.CrawlTVPadInfoErr)
			vodservice.UpdateVodTVStatus(crawlTvDto, vodservice.CrawlTVPadInfoErr)
		} else {
			ctx.Log.Infof(gctx.GetInitCtx(),
				"pad info. update vod id = %v, to status = %v", crawlTvDto.Id, vodservice.CrawlTVInit)
			vodservice.UpdateVodTVStatus(crawlTvDto, vodservice.CrawlTVInit)
		}
		return
	}

	region := browserutil.GetTextByXpath(ctx.Wd, "//*[@class='qy-player-tag']/a[contains(@href,'regionId')]")
	year := browserutil.GetTextByXpath(ctx.Wd, "//*[@class='qy-player-tag']/a[contains(@href,'year')]")
	tag := browserutil.GetTextByXpath(ctx.Wd, "//*[@class='qy-player-tag']/a[contains(@href,'showTy')]")
	quality := browserutil.GetTextByXpath(ctx.Wd, "//*[@id='playResolutions']/a")
	language := browserutil.GetTextByXpath(ctx.Wd, "//*[@id='playLangs']/a")

	ctx.Log.Infof(gctx.GetInitCtx(),
		"pad info. crawl region = %v, year = %v, quality = %v, language = %v, tag = %v, ", region, year, quality, language, tag)
	// 集数：//*[@id='play-list']//li
	// 当前选中的集数：//*[@id='play-list']//li[@class='select-item  selected']

	crawlTvDto.VideoCountry = region
	crawlTvDto.VideoYear = year
	crawlTvDto.VideoQuality = quality
	crawlTvDto.VideoLanguage = language
	crawlTvDto.VideoTag = tag

	introDetails := browserutil.GetTextArrayByXpath(ctx.Wd, "//*[@class='intro-detail']/li")
	for _, intro := range introDetails {
		if gstr.Contains(intro, "导演") {
			crawlTvDto.VideoDirector = gstr.Replace(intro, "导演:", "")
		} else if gstr.Contains(intro, "主演") {
			crawlTvDto.VideoActor = gstr.Replace(intro, "主演:", "")
		} else if gstr.Contains(intro, "简介") {
			crawlTvDto.VideoDesc = gstr.Replace(intro, "简介:", "")
		}
	}

	ctx.Log.Infof(gctx.GetInitCtx(),
		"pad info. update vod id = %v, to status = %v", crawlTvDto.Id, vodservice.CrawlTVPadInfoOK)
	vodservice.UpdateVodTVStatus(crawlTvDto, vodservice.CrawlTVPadInfoOK)

	vodTvItemElements, _ := ctx.Wd.FindElements(selenium.ByXPATH, "//*[@id='play-list']//li/a")
	ctx.Log.Infof(gctx.GetInitCtx(),
		"pad info. episodes size = %v", len(vodTvItemElements))

	for _, voTvItemEle := range vodTvItemElements {
		vodTvItem := new(entity.CmsCrawlVodTvItem)
		vodTvItem.CreateTime = gtime.Now()
		vodTvItem.TvId = crawlTvDto.Id
		href, _ := voTvItemEle.GetAttribute("href")
		episodes, _ := voTvItemEle.Text()
		if href == "" || episodes == "" {
			continue
		}
		vodItemMd5 := gmd5.MustEncryptString(href)
		if vodservice.GetVodTvItemByMd5(vodItemMd5) != nil {
			continue
		}
		vodTvItem.TvItemMd5 = vodItemMd5
		vodTvItem.CrawlStatus = vodservice.CrawlTVItemInit
		vodTvItem.SeedUrl = href
		vodTvItem.Episodes = episodes
		_, _ = dao.CmsCrawlVodTvItem.Ctx(gctx.GetInitCtx()).Save(vodTvItem)

	}

}

func isEmptyNiVodElement(text string) bool {
	return text == "-" || text == ""
}
